package com.jiuwan.gamepass.auth;

import com.fasterxml.jackson.core.filter.TokenFilter;
import com.jiuwan.gamepass.service.userImpl.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsUtils;

/**
 * @version 1.0
 * 功能目的描述 ：用于         ========>>>>>>>>>>>
 * @author： pang-yun
 * @date： 2021-06-11 09:05
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)//开启方法级别安全配置功能！
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;


    //登录成功的处理器
    @Autowired
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;

    //登录失败的处理器
    @Autowired
    private MyAuthenticationFailureHandler myAuthenticationFailureHandler;

    //匿名用户无权限访问时异常
    @Autowired
    private MyAuthenticationEntryPoint myAuthenticationEntryPoint;

    //权限不足处理器
    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;

    //注销操作处理器
    @Autowired
    private MyLogoutHandler myLogoutHandler;
    //注销成功处理器
    @Autowired
    private MyLogoutSuccessHandler myLogoutSuccessHandler;

    //超时处理器
    @Autowired
    private MyInvalidSessionStrategy myInvalidSessionStrategy;

    //被挤下线时的处理方式
    @Autowired
    private MyExpiredSessionStrategy myExpiredSessionStrategy;


    @Bean
    public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {
        return new JwtAuthenticationTokenFilter();
    }

    /**
     * 通过auth可以在内存中构建虚拟的用户名和密码
     *
     * @param auth
     * @throws Exception
     */
    //配置认证方式等
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);


    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
    }

    //http相关的配置，包括登入登出、异常处理、会话管理等
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //禁用缓存
        http.headers().cacheControl().disable();
        //关闭跨域攻击
        http.csrf().disable()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS); //会话创建方式 ，前后端分离采用jwt ,不需要session


        //表单
        //任何请求都会被认证，所有请求都会被拦截，包括登录   那么登录页面也无法进入
        http
                .addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class)
                .authorizeRequests()
                // 注意这里，是允许前端跨域联调的一个必要配置
                .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
                // 放行OPTIONS请求
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                //允许一下接口登录访问
                .antMatchers("/login", "/logout", "/user/addUser", "/SDKController/*", "/upload/*"
                        , "/SDK/*", "/backGround/*", "/material/*","/captcha","/loginPlus"
                ).permitAll()


                //所有请求都需要经过rabc测试，只有返回true才会允许访问
                .anyRequest()
                .access("@rbacService.hasPermission(request,authentication)");


        // 添加自定义未授权和未登录方法
        http.exceptionHandling()
                //未登录访问资源时提示的异常
                .authenticationEntryPoint(myAuthenticationEntryPoint)
                //权限不足时提示的异常
                .accessDeniedHandler(myAccessDeniedHandler);

        // 关闭csrf和frameOptions，如果不关闭会影响前端请求接口
        http.headers().frameOptions().disable();


    }
}
